2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 * Public License for more details.
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #import <Adium/AIAccountControllerProtocol.h>
18 #import <Adium/AIChatControllerProtocol.h>
19 #import <Adium/AIInterfaceControllerProtocol.h>
20 #import <Adium/AIStatusControllerProtocol.h>
21 #import <Adium/AIContactControllerProtocol.h>
22 #import <Adium/AIListObject.h>
23 #import "CBStatusMenuItemPlugin.h"
24 #import "CBStatusMenuItemController.h"
25 #import "AIMenuBarIcons.h"
26 #import <AIUtilities/AIApplicationAdditions.h>
27 #import <AIUtilities/AIMenuAdditions.h>
28 #import <AIUtilities/AIEventAdditions.h>
29 #import <AIUtilities/AIArrayAdditions.h>
30 #import <AIUtilities/AIImageAdditions.h>
31 #import <Adium/AIAccount.h>
32 #import <Adium/AIChat.h>
33 #import <Adium/AIListContact.h>
34 #import <Adium/AIStatusIcons.h>
35 #import <Adium/AIStatusMenu.h>
36 #import <Adium/AIAccountMenu.h>
37 #import <Adium/AIContactMenu.h>
38 #import <AIUtilities/AIColorAdditions.h>
39 #import <AIUtilities/AIStringAdditions.h>
40 #import <Adium/AIPreferenceControllerProtocol.h>
41 // For the KEY_SHOW_OFFLINE_CONTACTS and PREF_GROUP_CONTACT_LIST_DISPLAY
42 #import "AIContactController.h"
44 #define STATUS_ITEM_MARGIN 8
46 @interface CBStatusMenuItemController (PRIVATE)
47 - (void)activateAdium:(id)sender;
48 - (void)setIconImage:(NSImage *)inImage;
49 - (NSImage *)badgeDuck:(NSImage *)duckImage withImage:(NSImage *)inImage;
50 - (void)updateMenuIcons;
51 - (void)updateMenuIconsBundle;
52 - (void)updateUnreadCount;
53 - (void)updateOpenChats;
56 @implementation CBStatusMenuItemController
58 + (CBStatusMenuItemController *)statusMenuItemController
60 return [[[self alloc] init] autorelease];
65 if ((self = [super init])) {
66 //Create and set up the status item
67 statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain];
68 [statusItem setHighlightMode:YES];
71 [self updateMenuIconsBundle];
74 mainMenu = [[NSMenu alloc] init];
75 [mainMenu setDelegate:self];
77 mainContactsMenu = [[NSMenu alloc] init];
78 [mainContactsMenu setDelegate:self];
80 mainAccountsMenu = [[NSMenu alloc] init];
81 [mainAccountsMenu setDelegate:self];
83 // Set the main menu as the status item's menu
84 [statusItem setMenu:mainMenu];
86 // Create the caches for our menu items
87 accountMenuItemsArray = [[NSMutableArray alloc] init];
88 stateMenuItemsArray = [[NSMutableArray alloc] init];
89 openChatsArray = [[NSMutableArray alloc] init];
90 contactMenuItemsArray = [[NSMutableArray alloc] init];
92 // Flag all the menus as needing updates
93 mainMenuNeedsUpdate = YES;
94 contactsMenuNeedsUpdate = YES;
95 accountsMenuNeedsUpdate = YES;
97 NSNotificationCenter *notificationCenter = [adium notificationCenter];
98 //Register to recieve chat opened and chat closed notifications
99 [notificationCenter addObserver:self
100 selector:@selector(updateOpenChats)
103 [notificationCenter addObserver:self
104 selector:@selector(updateOpenChats)
107 [notificationCenter addObserver:self
108 selector:@selector(updateOpenChats)
109 name:Chat_OrderDidChange
112 [notificationCenter addObserver:self
113 selector:@selector(updateMenuIcons)
114 name:AIStatusIconSetDidChangeNotification
117 // Register for our menu bar icon set changing
118 [[adium notificationCenter] addObserver:self
119 selector:@selector(menuBarIconsDidChange:)
120 name:AIMenuBarIconsDidChangeNotification
123 // Register as a chat observer so we can know the status of unread messages
124 [[adium chatController] registerChatObserver:self];
126 // Register as a list object observer so we can know when accounts need to show reconnecting
127 [[adium contactController] registerListObjectObserver:self];
129 // Register as an observer of the preference group so we can update our "show offline contacts" option
130 [[adium preferenceController] registerPreferenceObserver:self
131 forGroup:PREF_GROUP_CONTACT_LIST_DISPLAY];
133 // Register as an observer of our own preference group
134 [[adium preferenceController] registerPreferenceObserver:self
135 forGroup:PREF_GROUP_STATUS_MENU_ITEM];
137 //Register to recieve active state changed notifications
138 [notificationCenter addObserver:self
139 selector:@selector(updateMenuIcons)
140 name:AIStatusActiveStateChangedNotification
143 //Register ourself for the status menu items
144 statusMenu = [[AIStatusMenu statusMenuWithDelegate:self] retain];
147 accountMenu = [[AIAccountMenu accountMenuWithDelegate:self
148 submenuType:AIAccountStatusSubmenu
149 showTitleVerbs:NO] retain];
152 contactMenu = [[AIContactMenu contactMenuWithDelegate:self
153 forContactsInObject:nil] retain];
161 // Invalidate and release our timers
162 [self invalidateTimers];
165 [[adium contactController] unregisterListObjectObserver:self];
166 [[adium chatController] unregisterChatObserver:self];
167 [[adium notificationCenter] removeObserver:self];
168 [[adium preferenceController] unregisterPreferenceObserver:self];
170 //Release our objects
171 [[statusItem statusBar] removeStatusItem:statusItem];
173 // All the temporary NSMutableArrays we store
174 [accountMenuItemsArray release];
175 [stateMenuItemsArray release];
176 [openChatsArray release];
177 [contactMenuItemsArray release];
181 [mainContactsMenu release];
182 [mainAccountsMenu release];
184 // Release our various menus.
185 [accountMenu setDelegate:nil]; [accountMenu release];
186 [contactMenu setDelegate:nil]; [contactMenu release];
187 [statusMenu setDelegate:nil]; [statusMenu release];
189 // Release our AIMenuBarIcons bundle
192 // Can't release this because it causes a crash on quit. rdar://4139755, rdar://4160625, and #743. --boredzo
193 // [statusItem release];
195 //To the superclass, Robin!
199 //Icon State --------------------------------------------------------
200 #pragma mark Icon State
202 #define PREF_GROUP_APPEARANCE @"Appearance"
203 #define KEY_MENU_BAR_ICONS @"Menu Bar Icons"
204 #define EXTENSION_MENU_BAR_ICONS @"AdiumMenuBarIcons"
205 #define RESOURCE_MENU_BAR_ICONS @"Menu Bar Icons"
207 - (void)updateMenuIconsBundle
209 NSString *menuIconPath = nil, *menuIconName;
211 menuIconName = [[adium preferenceController] preferenceForKey:KEY_MENU_BAR_ICONS
212 group:PREF_GROUP_APPEARANCE
215 // Get the path of the pack if found.
217 menuIconPath = [adium pathOfPackWithName:menuIconName
218 extension:EXTENSION_MENU_BAR_ICONS
219 resourceFolderName:RESOURCE_MENU_BAR_ICONS];
222 // If the pack is not found, get the default one.
223 if (!menuIconPath || !menuIconName) {
224 menuIconName = [[adium preferenceController] defaultPreferenceForKey:KEY_MENU_BAR_ICONS
225 group:PREF_GROUP_APPEARANCE
227 menuIconPath = [adium pathOfPackWithName:menuIconName
228 extension:EXTENSION_MENU_BAR_ICONS
229 resourceFolderName:RESOURCE_MENU_BAR_ICONS];
233 menuIcons = [[AIMenuBarIcons alloc] initWithURL:[NSURL fileURLWithPath:menuIconPath]];
235 [self updateMenuIcons];
238 // Updates the unread count of the status item.
239 - (void)updateUnreadCount
241 int unreadCount = [[adium chatController] unviewedContentCount];
243 // Only show if enabled and greater-than zero; otherwise, set to nil.
244 if (showUnreadCount && unreadCount > 0) {
245 [statusItem setTitle:[NSString stringWithFormat:@"%i", unreadCount]];
247 [statusItem setTitle:nil];
251 // Flashes unviewed content.
252 - (void)updateUnviewedContentFlash:(NSTimer *)timer
254 // Invert our current setting
255 currentlyIgnoringUnviewed = !currentlyIgnoringUnviewed;
256 // Update our current menu icon
257 [self updateMenuIcons];
260 - (void)invalidateTimers
262 currentlyIgnoringUnviewed = NO;
263 [unviewedContentFlash invalidate];
264 [unviewedContentFlash release]; unviewedContentFlash = nil;
267 #define IMAGE_TYPE_CONTENT @"Content"
268 #define IMAGE_TYPE_AWAY @"Away"
269 #define IMAGE_TYPE_IDLE @"Idle"
270 #define IMAGE_TYPE_INVISIBLE @"Invisible"
271 #define IMAGE_TYPE_OFFLINE @"Offline"
272 #define IMAGE_TYPE_ONLINE @"Online"
274 - (void)updateMenuIcons
276 NSImage *badge = nil;
277 BOOL anyAccountHasStatusMessage;
279 NSEnumerator *enumerator;
282 // If there's content, set our badge to the "content" icon.
283 if (unviewedContent && !currentlyIgnoringUnviewed) {
285 badge = [AIStatusIcons statusIconForStatusName:@"content"
286 statusType:AIAvailableStatusType
287 iconType:AIStatusIconList
288 direction:AIIconNormal];
291 imageName = IMAGE_TYPE_CONTENT;
293 // Get the correct icon for our current state.
294 switch([[[adium statusController] activeStatusState] statusType]) {
295 case AIAwayStatusType:
297 badge = [[[adium statusController] activeStatusState] icon];
300 imageName = IMAGE_TYPE_AWAY;
303 case AIInvisibleStatusType:
305 badge = [[[adium statusController] activeStatusState] icon];
308 imageName = IMAGE_TYPE_INVISIBLE;
311 case AIOfflineStatusType:
312 imageName = IMAGE_TYPE_OFFLINE;
316 // Online badging order of presence: idle > reconnecting account > status message
318 // Assuming we're using an online image unless proven otherwise
319 imageName = IMAGE_TYPE_ONLINE;
321 // Check idle here, since it has less precedence than offline, invisible, or away.
322 anyAccountHasStatusMessage = NO;
323 enumerator = [[[adium accountController] accounts] objectEnumerator];
325 // Check each account for IdleSince, a StatusState status message, or "Waiting to Reconnect"
326 while ((account = [enumerator nextObject])) {
327 if ([account online] && [account statusObjectForKey:@"IdleSince"]) {
329 badge = [AIStatusIcons statusIconForStatusName:@"Idle"
330 statusType:AIAvailableStatusType
331 iconType:AIStatusIconList
332 direction:AIIconNormal];
335 imageName = IMAGE_TYPE_IDLE;
337 // We don't need to check anymore; idle has high precedence than offline or available with a status message.
339 } else if (showBadge &&
340 ([account statusObjectForKey:@"Waiting to Reconnect"] ||
341 [[account statusObjectForKey:@"Connecting"] boolValue])) {
342 badge = [AIStatusIcons statusIconForStatusName:@"Offline"
343 statusType:AIOfflineStatusType
344 iconType:AIStatusIconList
345 direction:AIIconNormal];
346 } else if ([account online] && [[account statusObjectForKey:@"StatusState"] statusMessage]) {
347 anyAccountHasStatusMessage = YES;
351 // If we already haven't chosen a badge (for example, offline for a reconnecting account)
352 // and we have a status message set on any online account, use an online badge
353 if (showBadge && !badge && anyAccountHasStatusMessage) {
354 badge = [[[adium statusController] activeStatusState] icon];
361 NSImage *menuIcon = [menuIcons imageOfType:imageName alternate:NO];
362 NSImage *alternateMenuIcon = [menuIcons imageOfType:imageName alternate:YES];
365 [statusItem setImage:[self badgeDuck:menuIcon withImage:badge]];
366 // Badge the highlight image and set it.
367 [statusItem setAlternateImage:[self badgeDuck:alternateMenuIcon withImage:badge]];
368 // Update our unread count.
369 if (showUnreadCount) {
370 [self updateUnreadCount];
374 - (NSImage *)badgeDuck:(NSImage *)duckImage withImage:(NSImage *)badgeImage
376 NSImage *image = duckImage;
379 image = [[duckImage copy] autorelease];
383 NSRect srcRect = { NSZeroPoint, [badgeImage size] };
384 //Draw in the lower-right quadrant.
386 { .x = srcRect.size.width, .y = 0.0 },
389 destRect.size.width *= 0.5;
390 destRect.size.height *= 0.5;
392 //If the badge is bigger than that portion, resize proportionally. Otherwise, leave it alone and adjust the destination origin appropriately.
393 if ((srcRect.size.width > destRect.size.width) || (srcRect.size.height > destRect.size.height)) {
394 //Resize the dest rect.
396 if (srcRect.size.width > srcRect.size.height) {
397 scale = destRect.size.width / srcRect.size.width;
399 scale = destRect.size.height / srcRect.size.height;
402 destRect.size.width = srcRect.size.width * scale;
403 destRect.size.height = srcRect.size.height * scale;
405 //Make sure we scale in a pretty manner.
406 [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
409 //Move the drawing origin.
410 destRect.origin.x = [duckImage size].width - destRect.size.width;
412 [badgeImage drawInRect:destRect
414 operation:NSCompositeSourceOver
422 //Account Menu --------------------------------------------------------
423 #pragma mark Account Menu
424 - (void)accountMenu:(AIAccountMenu *)inAccountMenu didRebuildMenuItems:(NSArray *)menuItems {
425 // Going from or to 1 account requires a main menu update
426 if ([accountMenuItemsArray count] == 1 || [menuItems count] == 1)
427 mainMenuNeedsUpdate = YES;
430 [accountMenuItemsArray release];
431 accountMenuItemsArray = [menuItems retain];
433 //We need to update next time we're clicked
434 accountsMenuNeedsUpdate = YES;
437 - (void)accountMenu:(AIAccountMenu *)inAccountMenu didSelectAccount:(AIAccount *)inAccount {
438 [inAccount toggleOnline];
442 //Status Menu --------------------------------------------------------
443 #pragma mark Status Menu
444 - (void)statusMenu:(AIStatusMenu *)inStatusMenu didRebuildStatusMenuItems:(NSArray *)menuItemArray
446 [stateMenuItemsArray release];
447 stateMenuItemsArray = [menuItemArray retain];
449 //We need to update next time we're clicked
450 mainMenuNeedsUpdate = YES;
453 //Contact Menu --------------------------------------------------------
454 #pragma mark Contact Menu
455 - (void)contactMenu:(AIContactMenu *)inContactMenu didRebuildMenuItems:(NSArray *)menuItems
457 // Going from or to 0 contacts requires a main menu update
458 if ([contactMenuItemsArray count] == 0 || [menuItems count] == 0)
459 mainMenuNeedsUpdate = YES;
461 [contactMenuItemsArray release];
462 contactMenuItemsArray = [menuItems retain];
464 // Update the next time we're clicked.
465 contactsMenuNeedsUpdate = YES;
468 - (void)contactMenu:(AIContactMenu *)inContactMenu didSelectContact:(AIListContact *)inContact
470 [[adium interfaceController] setActiveChat:[[adium chatController] openChatWithContact:inContact
471 onPreferredAccount:YES]];
472 [self activateAdium:nil];
475 - (BOOL)contactMenu:(AIContactMenu *)inContactMenu shouldIncludeContact:(AIListContact *)inContact
477 // Show this contact if we're showing offline contacts or if this contact is online.
478 return [inContact visible];
481 - (BOOL)contactMenuShouldDisplayGroupHeaders:(AIContactMenu *)inContactMenu
483 return showContactGroups;
486 - (BOOL)contactMenuShouldUseDisplayName:(AIContactMenu *)inContactMenu
491 - (BOOL)contactMenuShouldUseUserIcon:(AIContactMenu *)inContactMenu
496 //List Object Observer -------------------------------------------------
497 #pragma mark List Object Observer
498 - (NSSet *)updateListObject:(AIListObject *)inObject keys:(NSSet *)inModifiedKeys silent:(BOOL)silent
500 if ([inObject isKindOfClass:[AIAccount class]]) {
501 if ([inModifiedKeys containsObject:@"Connecting"] ||
502 [inModifiedKeys containsObject:@"Waiting to Reconnect"]) {
503 [self updateMenuIcons];
510 //Chat Observer --------------------------------------------------------
511 #pragma mark Chat Observer
513 - (NSSet *)updateChat:(AIChat *)inChat keys:(NSSet *)inModifiedKeys silent:(BOOL)silent
515 [self updateOpenChats];
517 // We didn't modify anything; return nil.
521 - (void)updateOpenChats
525 int unviewedContentCount = [[adium chatController] unviewedContentCount];
527 // Update our open chats
528 [openChatsArray release];
529 openChatsArray = [[[adium interfaceController] openChats] retain];
531 // We think there's unviewed content, but there's not.
532 if (unviewedContent && unviewedContentCount == 0) {
533 // Invalidate and release the unviewed content flash timer
534 [unviewedContentFlash invalidate];
535 [unviewedContentFlash release]; unviewedContentFlash = nil;
536 currentlyIgnoringUnviewed = NO;
538 // Update unviewed content
539 unviewedContent = NO;
541 // Update our menu icons
542 [self updateMenuIcons];
543 // We think there's no unviewed content, and there is.
544 } else if (!unviewedContent && unviewedContentCount > 0) {
545 // If this particular Xtra wants us to flash unviewed content, start the timer up
547 currentlyIgnoringUnviewed = NO;
548 unviewedContentFlash = [[NSTimer scheduledTimerWithTimeInterval:1.0
550 selector:@selector(updateUnviewedContentFlash:)
552 repeats:YES] retain];
555 // Update unviewed content
556 unviewedContent = YES;
558 // Update our menu icons
559 [self updateMenuIcons];
560 // If we already know there's unviewed content, just update the count.
561 } else if (unviewedContent && unviewedContentCount > 0) {
562 [self updateUnreadCount];
565 mainMenuNeedsUpdate = YES;
570 //Menu Delegates/Actions --------------------------------------------------------
571 #pragma mark Menu Delegates/Actions
572 - (void)menuNeedsUpdate:(NSMenu *)menu
574 // Main menu if not holding option key
575 if (![NSEvent optionKey] && (menu == mainMenu && mainMenuNeedsUpdate)) {
576 NSEnumerator *enumerator;
577 NSMenuItem *menuItem;
579 //Clear out all the items, start from scratch
580 [menu removeAllItems];
582 //Add the state menu items
583 enumerator = [stateMenuItemsArray objectEnumerator];
585 while ((menuItem = [enumerator nextObject])) {
586 [menu addItem:menuItem];
588 //Validate the menu items as they are added since they weren't previously validated when the menu was clicked
589 if ([[menuItem target] respondsToSelector:@selector(validateMenuItem:)]) {
590 [[menuItem target] validateMenuItem:menuItem];
594 [menu addItem:[NSMenuItem separatorItem]];
596 // If there's more than one account, show the accounts menu
597 if ([accountMenuItemsArray count] > 1) {
598 menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Accounts",nil)
603 [menuItem setSubmenu:mainAccountsMenu];
604 [menu addItem:menuItem];
608 // Show the contacts menu if we have any contacts to display
609 if ([contactMenuItemsArray count] > 0) {
611 menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Contacts",nil)
616 [menuItem setSubmenu:mainContactsMenu];
617 [menu addItem:menuItem];
620 [menu addItemWithTitle:[AILocalizedString(@"Contact List", nil) stringByAppendingEllipsis]
622 action:@selector(activateContactList:)
626 //If there exist any open chats, add them
627 if ([openChatsArray count] > 0) {
630 enumerator = [openChatsArray objectEnumerator];
633 [menu addItem:[NSMenuItem separatorItem]];
635 //Create and add the menu items
636 while ((chat = [enumerator nextObject])) {
637 NSImage *image = nil;
638 //Create a menu item from the chat
639 menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[chat displayName]
641 action:@selector(switchToChat:)
643 //Set the represented object
644 [menuItem setRepresentedObject:chat];
648 //If there is a chat status image, use that
649 image = [AIStatusIcons statusIconForChat:chat type:AIStatusIconMenu direction:AIIconNormal];
650 //Otherwise use the chat's -chatMenuImage
652 image = [chat chatMenuImage];
655 [menuItem setImage:image];
658 [menu addItem:menuItem];
663 //Only update next time if we need to
664 mainMenuNeedsUpdate = NO;
665 // Contacts menu - or, override the main menu with option held down
666 } else if (((menu == mainMenu) && [NSEvent optionKey]) || ((menu == mainContactsMenu) && contactsMenuNeedsUpdate)) {
667 NSEnumerator *enumerator = [contactMenuItemsArray objectEnumerator];
668 NSMenuItem *menuItem;
670 // Remove previous menu items.
671 [menu removeAllItems];
673 // If this is the contact menu being pushed into the main one, force an update next time
674 if ([NSEvent optionKey]) {
675 // Remove contact menu items from the old menu
676 [mainContactsMenu removeAllItems];
677 // Have both menus update next time
678 mainMenuNeedsUpdate = YES;
679 contactsMenuNeedsUpdate = YES;
681 contactsMenuNeedsUpdate = NO;
684 [menu addItemWithTitle:[AILocalizedString(@"Contact List", nil) stringByAppendingEllipsis]
686 action:@selector(activateContactList:)
689 if ([contactMenuItemsArray count] > 0)
690 [menu addItem:[NSMenuItem separatorItem]];
692 while ((menuItem = [enumerator nextObject])) {
693 [menu addItem:menuItem];
695 //Validate the menu items as they are added since they weren't previously validated when the menu was clicked
696 if ([[menuItem target] respondsToSelector:@selector(validateMenuItem:)]) {
697 [[menuItem target] validateMenuItem:menuItem];
701 } else if (menu == mainAccountsMenu && accountsMenuNeedsUpdate) {
702 NSEnumerator *enumerator = [accountMenuItemsArray objectEnumerator];
703 NSMenuItem *menuItem;
705 [menu removeAllItems];
707 [menu addItemWithTitle:[AILocalizedString(@"Account List", nil) stringByAppendingEllipsis]
709 action:@selector(activateAccountList:)
712 [menu addItem:[NSMenuItem separatorItem]];
714 //Add the account menu items
715 enumerator = [accountMenuItemsArray objectEnumerator];
716 while ((menuItem = [enumerator nextObject])) {
719 [menu addItem:menuItem];
721 //Validate the menu items as they are added since they weren't previously validated when the menu was clicked
722 if ([[menuItem target] respondsToSelector:@selector(validateMenuItem:)]) {
723 [[menuItem target] validateMenuItem:menuItem];
726 submenu = [menuItem submenu];
728 NSEnumerator *submenuEnumerator = [[submenu itemArray] objectEnumerator];
729 NSMenuItem *submenuItem;
730 while ((submenuItem = [submenuEnumerator nextObject])) {
731 //Validate the submenu items as they are added since they weren't previously validated when the menu was clicked
732 if ([[submenuItem target] respondsToSelector:@selector(validateMenuItem:)]) {
733 [[submenuItem target] validateMenuItem:submenuItem];
739 accountsMenuNeedsUpdate = NO;
743 - (void)switchToChat:(id)sender
745 [[adium interfaceController] setActiveChat:[sender representedObject]];
746 [self activateAdium:nil];
749 - (void)activateContactList:(id)sender
751 [[adium interfaceController] showContactList:nil];
752 [self activateAdium:nil];
755 - (void)activateAccountList:(id)sender
757 [[adium preferenceController] openPreferencesToCategoryWithIdentifier:@"Accounts"];
758 [self activateAdium:nil];
761 - (void)activateAdium:(id)sender
763 if (![NSApp isActive]) {
764 [NSApp activateIgnoringOtherApps:YES];
765 [NSApp arrangeInFront:nil];
769 #pragma mark Preferences Observer
770 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
771 object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
773 if ([group isEqualToString:PREF_GROUP_CONTACT_LIST_DISPLAY]) {
774 showContactGroups = ![[prefDict objectForKey:KEY_HIDE_CONTACT_LIST_GROUPS] boolValue];
775 [contactMenu rebuildMenu];
778 if ([group isEqualToString:PREF_GROUP_STATUS_MENU_ITEM]) {
779 showUnreadCount = [[prefDict objectForKey:KEY_STATUS_MENU_ITEM_COUNT] boolValue];
780 showBadge = [[prefDict objectForKey:KEY_STATUS_MENU_ITEM_BADGE] boolValue];
781 flashUnviewed = [[prefDict objectForKey:KEY_STATUS_MENU_ITEM_FLASH] boolValue];
783 [self updateMenuIcons];
784 [self updateUnreadCount];
790 - (void)menuBarIconsDidChange:(NSNotification *)notification
792 [self updateMenuIconsBundle];